De volksbank is het moederbedrijf van ASN, SNS, BLG en Regiobank. Als de vierde bank van Nederland, financiert de volksbank hypotheken, beheert ze spaargeld en biedt de bank klanten een betaalrekening. Binnen de afdeling Financial Markets van de Volksbank, hebben de macro economen van de Volksbank als taak de toestand in de economie te monitoren en toe te lichten aan directie en beleidsmakers. Een belangrijk onderdeel daarvan heeft betrekking met de ontwikkeling van de hypotheekmarkt in Nederland. De huizenmarkt is een belangrijke factor in de beleidsontwikkeling van de bank, met betrekking tot de hypotheekproductie.
De huizenprijzen en aantallen verkochte woningen zijn de belangrijkste indicatoren voor de ontwikkeling van de hypotheekmarkt.
Voor deze analyse is de PPDAC cyclus ( Problem, Plan, Data, Analysis, and Conclusions) gevolgd. Een methode voor het uitvoeren van statististch onderzoek [OldfordR.J.MacKay2000]. De opbouw van dit verslag volgt deze cyclus. In de volgende paragraaf wordt eerst de probleemstelling nader toegelicht. Vervolgens is in de planningsfase een literatuurstudie uitgevoerd om de belangrijkste factoren te bepalen die nodig zijn om de vraagstelling te beantwoorden. De data benodigd voor dit onderzoek is daarna verzameld en vervolgens geanalyseerd. Op basis daarvan worden tot slot een aantal conclusies getrokken. Deze cyclus is een aantal keer doorlopen - op basis van de uitkomsten. Dit komt terug in de probleemstelling en de uitwerking van deze casus.
Uit het overleg met de macro economen is de vraag naar voren gekomen of een beter voorspellend model kan worden ontwikkeld voor de huizenmarkt in Nederland.
Is het mogelijk om modellen te ontwikkelen die de huizenprijs op middellange termijn voorspelt en het aantal transacties op de huizenmarkt op middellange termijn voorspelt?"
Vanuit de Volksbank is in het verleden al eerder statistisch onderzoek gedaan naar deze vebanden. Data werd hierbij verzameld via Datascope (Refinitiv) en geanalyseerd in Excel.
Voor de huizenprijzen is eerder gekeken naar een verband tussen huizenprijzen en de werkgelegenheid, lonen, GDP en rente. Hieruit is een eenvoudig model ontwikkeld waarbij met name het verband met GDP wordt gebruikt om de ontwikkeling van de huizenprijzen te voorspellen. Voor het aantal transacties op de lange termijn wordt een verband verondersteld met het aantal huishoudens. op kortere termijn spelen economische groei, rentestanden en evt. regelgeving ook een rol.
In deze exploratie wil ik kijken naar mogelijke factoren die effect hebben op de marktprijs. Het is in deze fase nog niet de ambitie om ook daadwerkelijk een alternatief model te ontwikkelen voor het voorspellen van de marktprijzen en aantal transacties.
Welke factoren spelen een belangrijke rol in het bepalen van de huizenprijzen en transactie volumes op een termijn van 5 tot 10 jaar?
Aanvullend zijn er een aantal vragen geformuleerd waar mogelijk door middel van exploratie iets meer over te weten kunnen komen:
Nederland heeft een van de hoogste persoonlijke schulden (hypotheeklast) in de wereld. Wat zijn de gevolgen voor de hypotheekmarkt van het gewijzigde beleid? Heeft dit effect op de huizenprijzen?
Hoe ontwikkeld de krapte op de huizenmarkt zich, op termijn? Momenteel zijn er ambiteuze plannen om ergens tussen de 75.000 en 100.000 woningen per jaar te gaan bouwen. Het aanbod aan huizen wordt dus groter - terwijl op termijn verwacht wordt dat de bevolking weer gaat krimpen. Kunnen we hier een voorspelling van maken?
Hoe zit het met de bevolkingsgroei? Welk deel van de aanwas in Nederland komt door migratie? Hoe zit dat regionaal? Is er nog sprake van verstedelijking na corona? Stroomt het platteland leeg - en de randstad vol? Welk effect heeft dit op de huizenprijzen?
Zien we demografisch verdeeld verschillen waar mensen willen wonen? Verhuizen gezinnen met kinderen naar het platteland, en ouderen weer naar de stad? Het aantal huishoudens dat uit 1 persoon bestaat is erg gegroeid in de loop der tijd - en zal (denk ik) nog wel doorstijgen met de vergrijzing. Betekent dit dat er meer mensen naar de stad willen verhuizen?
Hoe afhankelijk is de huizenmarkt van de stand van de economie? Gaan huizenprijzen alleen omhoog tijdens de groeifase van de economie?
De eerste deelvraag van dit onderzoek gaat in op de vraag in hoeverre de huizenprijzen wordt bepaald door vraag en aanbod.
Daarna wordt verder ingegaan op de factoren die op langere termijn de huizenprijzen beinvloeden en wordt gekeken of hier voorspellende waarde in zit. Vervolgens wordt gekeken naar de transactievolumes. Transactievolumes hebben waarschijnlijk een direct verband met het aantal huishoudens. Hierbij is gekeken of er seizoensinvloeden of trendmatigheden in de transactie volumes te ontdekken zijn.
Ten slot wordt kort ingegaan op de vraag of er regionaal verschillen zijn in de ontwikkeling van de huizenprijzen.
Om in ieder geval een begin te maken met het beantwoorden van deze vragen ben ik in gesprek gegaan met de specialisten bij de Volksbank. Aanvullend heb ik een korte literatuurstudie gedaan naar de factoren die op lange termijn de prijsstelling zouden beinvloeden.
In eerste instantie richt het onderzoek zich op de vraag en aanbod op de woningmarkt in Nederland. Het CBS publiceert vrij veel over de prijsonwikkeling van bestaande woningen, nieuwe woningen en de stand van de economie. De Socrates modellen sluiten goed aan bij deze vraagstelling (zie Kenneth Gopal, Gerard van Leeuwen, David Omtzigt, 2020).
Op langere termijn is de woningmarkt een markt van vraag en aanbod. Vraag en aanbod worden bepaald door:
Vraag woningen:
Aanbod woningen:
Daarna is verder ingegaan op de factoren die van invloed zijn bij de prijsonwikkeling op de woningmarkt. Hierbij kan een onderscheidt gemaakt worden in factoren die direct de prijsontwikkeling beinvloeden - en factoren die meer aanduiden of er sprake is van oververhitting (Groot, Vogt, Van der Wiel, & Van Dijk, 2018).
Indicatoren
Oververhitting
Het aantal transacties wordt met name bepaald door het aantal huishoudens. Daarnaast kan door krapte op de woningmarkt een schaarste ontstaan waardoor de woningmarkt ‘op slot’ geraakt. Tijdelijk zou prijsinelastisiteit er voor kunnen zorgen dat consumenten geen nieuwe woning betrekken omdat zij de huizen te duur vinden. Het consumentenvertrouwen speelt hierbij een belangrijke rol.
Indicatoren aantal transacties
De gewenste informatie is opgevraagd bij de statistici (via Reuters Datastream) en later aangevuld met open data van het CBS (Statline).
Voor het inlezen van de (spreadsheet) Reutersdata zijn een aantal functies ontwikkeld. Om de data van het CBS gemakkelijker in te kunnen lezen is een routine ontwikkeld die aan de hand van metadata de gevraagde data inleest. Routines voor het lezen en opschonen van de data, zijn opgeslagen in seperate R files.
De data die via die routines is gegenereerd wordt tussentijds opgeslagen in Rdata formaat - en kan voor de analyse hier direct worden ingelezen. Op deze wijze is een scheiding aangebracht tussen de data-acquisitie en de analyse van de resultaten.
Ter beperking van de omvang van dit onderzoek is een selecties gemaakt op basis van de beschikbare data.
Voor de indicatoren over de huizenprijzen zal ik mij alleen beperken tot het besteedbaar inkomen, de rente standen, particulier vermogen en werkloosheid en het consumenenvertrouwen.
Gegevens over de verhouding tussen huur en koopprijzen, het aantal te koop staande huizen, de gem. tijd dat een woning te koop staat en de prijsverschillen tussen aanbodprijs en transactieprijs zeggen iets over de mate van oververhitting van de markt (zie Groot et al. (2018)). Ik beschik echter niet over voldoende data om hier een tijdsanalyse over uit te voeren.
Voor de indicatoren over het aantal transacties beperk ik mij tot een tijdreeksanalyse van de transacties zelf. Langere termijn afhankelijkheden van de economie, het consumentenvertrouwen en het aantal huishoudens zullen er zeker zijn maar zijn vanwege de beperkte tijd voor dit onderzoek niet verder meegenomen.
library (tidyverse) # Tidyverse utilities (Wickham et al. 2019)
library (here) # here: A Simpler Way to Find Your Files (Müller 2020))
library (lubridate) # Dates and Times Made Easy (Grolemund, Wickham 2011))
library (reshape2) # Reshaping Data (Hadley Wickham 2007)
library (knitr) # A General-Purpose Package for Dynamic Report Generation (Xie 2021)
library (kableExtra) # Construct Complex Table with 'kable' and Pipe Syntax(Zhu 2021)
library (viridis) # Default Color Maps from 'matplotlib' (Garnier 2018)
library (forcats) # Tools for Working with Categorical Variables (Factors) (Wickham 2021)
library (forecast) # Forecasting functions for time series and linear models (Hyndman et al. 2021)
library (fpp2) # Data for "Forecasting: Principles and Practice" (Hyndman 2020)
library (zoo) # S3 Infrastructure for Regular and Irregular Time
# Series (Zeileis and Grothendieck 2005)
library (urca) # Analysis of Integrated and Cointegrated
# Time Series with R (Pfaff 2008)
library (cowplot) # Streamlined Plot Theme and Plot Annotations
# for 'ggplot2' (Claus O. Wilke 2020)
library (sjPlot) # Data Visualization for Statistics in Social Science (Lüdecke 2021)
library (sf) # Standardized Support for Spatial Vector Data (Pebesma 2018)
library (rsample) # General Resampling Infrastructure (Silge, Chow, Kuhn and Wickham 2021)
library (earth) # Multivariate Adaptive Regression Splines (Milborrow, 2020)
library (caret) # Classification and Regression Training (Kuhn 2020)
library (vip) # Variable Importance Plots (Greenwell and Boehmke 2020)
library (pdp) # Constructing Partial Dependence Plots (Greenwell 2017)
library (timetk) # A Tool Kit for Working with Time Series
# in R (Dancho and Vaughan 2021)
library (corrplot) # Visualization of a Correlation Matrix (Wei and Simko 2017)
library (stargazer) # Well-formatted regression summary statistics (Hlavac 2018)
library (dynlm) # Dynamic linair models and time series regression (Zeileis 2019)
library (broom) # Convert Statistical Objects into Tidy Tibbles (Robinson, Hayes and Couch 2021)
# Loading the datasets
dfs<-list.files(here("data","tidy"), pattern = "*.Rdata")
for(d in dfs) {
load(file= here("data","tidy",d ))
}
# Set default theme for all plots
theme_set(theme_minimal())
Prijzen van koopwoningen zijn de laatste jaren erg sterk toegenomen. We zien kleine verschillen per type woning. Waarbij met name appartementen de laatste tijd releatief duurder zijn geworden.
prijsindex_type_woning %>%
filter(type_woning != "Totaal woningen") %>%
filter(type_woning != "EGW") %>%
ggplot(aes(x=date, y=prijsindex_type_woning)) +
geom_line(aes(color = type_woning)) +
facet_wrap(~ type_woning) +
labs(
title = "Prijsindex Bestaande Koopwoningen (PBK)",
y = "",
x = '',
color = 'Type woning'
) +
theme(legend.position = "none")
Bij de factoren die de vraag naar woningen bepalen kijken we naar de ontwikkeling van het aantal huishoudens en de samenstelling van de huishoudens. Nederlanders worden steeds ouder, en gezinnen worden kleiner. Deze ontwikkeling leidt mogelijk tot een verschuiving in de vraag - van eensgezinswoningen naar kleinere woningen.
bevolking %>%
select (date, kl_20_jaar, v20_40_jaar, v40_65_jaar, v65_80_jaar, gd_80_jaar) %>%
filter (date >= as.Date("1995-01-01")) %>%
melt (id = c('date')) %>%
mutate ( variable = factor(variable),
variable = factor(variable, levels = rev(levels(variable)))) %>%
mutate (value = value / 1000) %>%
ggplot ( aes( x = date, y = value, fill = variable) ) +
geom_area(color = "darkgrey", stat = "identity", alpha = 0.8) +
labs(
title = "Bevolkingsgroei",
subtitle = "1995 tot 2020",
y = "Aantal (x 1000)",
x = '',
caption = "Bron: CBS, Bevolking; kerncijfers"
)
De groei van de Nederlandse bevolking wordt in de laatste jaren steeds meer bepaald door migratie. Het geboorteoverschot (aantal nieuw geborenen -/- aantal sterfgevallen is nog nooit zo laag geweest). Mogelijk zien we hierdoor een verschuiving in de vraag naar meer woningen in de steden.
bevolking %>%
select (date, geboorteoverschot, migratiesaldo) %>%
filter (date >= as.Date("1970-01-01")) %>%
melt (id = c('date')) %>%
mutate (value = value / 1000) %>%
drop_na %>%
ggplot(aes (x = date, y=value, fill = variable)) +
geom_bar(stat="identity") +
labs(
title = "Bevolkingsgroei",
y = "Aantal (x 1000)",
x = '',
fill = '',
caption = "Bron: CBS, Bevolking; kerncijfers"
)
Het CBS maakt regelmatig een prognose van de verwachte groei. Hier zien we dat deze trand zich de aankomende jaren voortzet. De groei komt voornamelijk door de groei van het aantal eenspersoonshuishoudens. Deze trend zet zich de aankomende jaren nog voort. De laatste prognoses zijn overigens van 2019. In de prognose zien we een afvlakking van de groei van het aantal huishoudens rond 2040.
aantal_hh <-
bevolking %>%
filter( date >= as.Date("1970-01-01")) %>%
select (date,
eenpersoonshuishoudens,
meerpersoonshuishoudens) %>%
melt(id = c('date')) %>%
set_names ('date','type_huishouden', 'aantal')
prognose_hh <-
prognose_huishoudens_2019 %>%
select (date,
eenpersoonshuishoudens,
meerpersoonshuishoudens) %>%
melt(id = c('date')) %>%
set_names ('date','type_huishouden', 'prognose') %>%
mutate(prognose = prognose / 1000)
aantal_hh %>%
ggplot(aes (x = date, y=value, fill = variable)) +
geom_area(aes(y=aantal,
fill= type_huishouden
)) +
geom_area(data = prognose_hh,
aes(y=prognose,
fill= type_huishouden,
alpha = 0.1
)) +
geom_vline(xintercept=max(aantal_hh$date), color="darkgray", size=1) +
labs(
title = "Prognose aantal huishoudens",
y = "Aantal (x 1000)",
x = '',
caption = "Bron: CBS, Bevolking; kerncijfers"
) +
theme(legend.title = element_blank()) +
guides(alpha = FALSE) +
annotate("text", x = max(aantal_hh$date), y = 0,
label = c(" Prognose") , color="black", hjust = 0, vjust = 1,
size=3)
Wanneer we een wat langere termijn trend kijken naar het aantal gerealiseerde nieuwbouwhuizen zien we dat het aantal nieuwbouwhuizen eigenlijk nu niet bijzonder hoog is. Ondanks dat er meer dan 70.000 huizen bijgebouwd wordt per jaar is dat vergeleken met de totale woningvoorraad eigenlijk niet bijzonder veel. Wel opvallend is dat de laatste jaren er meer overige toevoegingen en overige onttrekkingen geregistreerd worden. Mogelijk geeft dit aan dat de ruimte voor nieuwbouw schaarser wordt waardoor creatiever wordt omgegaan met de beschikbare ruimte.
voorraad_woningen %>%
select(date,
nieuwbouw,
overige_toevoegingen,
sloop,
Overige_onttrekking,
correctie
) %>%
mutate (sloop = - sloop ) %>%
mutate (Overige_onttrekking = - Overige_onttrekking) %>%
mutate (correctie = - correctie) %>%
filter( date >= as.Date("1970-01-01")) %>%
melt (id = c('date')) %>%
mutate (value = value / 1000) %>%
ggplot(aes(x=date, y = value, fill = variable )) +
geom_bar(stat="identity") +
geom_hline(yintercept = 0, color = "steelblue") +
labs ( title = "Ontwikkelingen woningvoorraad",
y = "Aantal (x 1000)",
x = "Jaar") +
guides(fill = guide_legend(title = ''))
#82235NED CBS Aantal Woningen
#Aantal huishoudens: NLHSTOTP Thomson Reuters
# Tidy data
df <-
aantal_huishoudens_per_jaar %>%
full_join(voorraad_woningen, by = c("date" = "date")) %>%
select (date,
aantal_huishoudens,
voorraad) %>%
set_names('date',
'huishoudens',
'woningvoorraad' ) %>%
mutate(te_kort = (woningvoorraad - huishoudens)) %>%
filter(date > as.Date("2000-01-01")) %>%
melt(id = c('date'))
# Line plot
lp<-
df %>%
filter (variable != 'te_kort') %>%
ggplot(aes (x = date)) +
geom_line(aes(y=value, color = variable)) +
labs(
title = "Aantal huishoudens vs voorraad woningen",
y = "Aantal (x 1000)",
x = '',
color = ''
)
# Bar plot
bp <-
df %>%
filter (variable == 'te_kort') %>%
ggplot(aes (x = date)) +
geom_bar(stat = "identity" ,
aes(y = value, fill = factor(variable, labels = c("Te Kort woningen")))) +
labs ( y = "Te kort (x 1000)",
x = "",
fill = "") +
theme( axis.text.x = element_blank(),
axis.ticks = element_blank())
cowplot::plot_grid(lp, bp, ncol=1, rel_heights = c(2, 1), align = 'v')
In bovenstaande grafiek zien we dat het aantal woningen al decenia lang gelijke tred houdt met het aantal woningen. Er is daarbij telkens wel een tekort zichtbaar. Dit is veel kleiner dan het door het CBS gerapporteerde tekort van 331.000 woningen [CBS2020b]. In de verdere analyse wordt uitgegaan van de tekorten zoals hier berekend. Dit is het verschil tussen het aantal huishoudens en de voorraad woningen.
Vanwege de (structurele) te korten op de woningmarkt lijken huizen prijzen in belangrijke mate beinvloed te worden door de financieringsmogelijkheden van de kopers. De rente is historisch laag, de inkomens zijn gestegen en het eigen vermogen is gegroeit. De fiscale behandeling en regelgeving speelt hier een belangrijke rol, zowel ruimte scheppend - verruimen van de leenmogelijkheden van tweeverdieners, als beperkend - beperking aftrekbaarheid tot 100% financiering.
# Huizenprijzen
prijsindex_woningen_lt %>%
ggplot(aes(x = date)) +
geom_line(aes( y = huisprijsindex), color = 'steelblue') +
labs(
title = "Huizenprijzen",
subtitle = "Index (2015 = 100)",
y = "",
x = ""
)
# GDP
gdp_lt %>%
ggplot( aes(x=date, y=gdp)) +
geom_line(color = 'steelblue') +
labs(
title = "Ontwikkeling BBP (Bruto Binnenlands Product) (j-op-j wijzigingen)",
y = "",
x = '',
caption = "Bron: OECD Economic Outlook"
)
# Rente
hypotheek_rente %>%
ggplot( aes(x=period, y=hypotheek_rente)) +
geom_line(color = 'steelblue') +
labs(
title = "Hypotheekrente",
y = "gemiddelde rente",
x = ''
)
# Werkgelegenheid
werkgelegenheid_lt %>%
ggplot(aes(x = period, y = werkgelegenheid)) +
geom_line(color = 'steelblue') +
labs(
title = "Werkgelegenheid",
y = "(x 1000)",
x = '',
caption = "Bron: OECD Economic Outlook"
)
# Inkomen
inkomen_lt %>%
ggplot(aes(x = period, y = inkomen)) +
geom_line(color = 'steelblue') +
labs(
title = "Inkomen per medewerker per kwartaal",
y = "EUR",
x = '',
caption = "Bron: Oxford Economics"
)
# Consumentenvertrouwen
consumenten_vertrouwen_lt_q %>%
mutate(pos = ifelse(consumer_conf >= 0,consumer_conf, 0)) %>%
mutate(neg = ifelse(consumer_conf < 0,consumer_conf, 0)) %>%
ggplot(aes(x = date)) +
geom_area(aes(y = pos), fill = 'steelblue') +
geom_area(aes(y = neg), fill = 'indianred2') +
geom_hline (yintercept = 0, color = 'steelblue') +
labs(
title = "Indicator Consumenten vertrouwen",
y = "",
x = ""
)
Over de vermogens van huishoudens is er helaas niet een langere termijn tijdsreeks beschikbaar. Een veronderstelling van dit onderzoek was dat door het gewijzigdde beleid en de stijgende huizenprijzen het vermogen van huishoudens zou stijgen. Daardoor heeft men ook weer meer vermogen beschikbaar voor de aanschaf van woningen wat een prijsopdrijvend effect zou hebben. Dit is door gebrek en data helaas niet verder te verifieren.
In deze studie is gekeken naar een aantal modellen om een voorspelling te kunnen doen over de ontwikkeling van de huizenprijzen. Voor alle modellen is de data tot en met 2015 genomen als trainingdata. Het model geeft daamee een voorspelling over de jaren 2016 tot 2020. Op deze wijze kunnen we een vergelijking maken tussen de modellen.
Om de voorspellende factoren vergelijkbaar te maken is gekeken naar de jaar-op-jaar wijzigingen in de factoren. Voor Bruto Binnenlands Product is dit zo aangeleverd. De overige indicatoren zijn omgerekend naar percentuele wijzging jaar-op-jaar.
Correlatie van huisprijzen
We vinden een correlatie tussen inkomen, werkgelegenheid, BBP en huizenprijzen. De verwachting is dat dit met name wordt veroorzaakt door de tijdswaarde. Over de jaren heen, stijgt het inkomen, daalt de rente, en stijgen de huizenprijzen.
# plot correlations
corMatrix <- round(cor(df_rm_huizenprijzen %>%
select(huisprijsindex_yoy,
werkgelegenheid_yoy,
hypotheek_rente_yoy,
gdp,
consumer_conf_yoy,
inkomen_yoy)),5)
corCols <- c("huisprijsindex",
"werkgelegenheid",
"hypotheekrente",
"BBP",
"Cons.Vertrouwen",
"Inkomen")
colnames(corMatrix) <- corCols
rownames(corMatrix) <- corCols
corrplot(corMatrix,
title = "Correlatie huizenprijzen",
type = "lower",
tl.cex = 0.8,
tl.col = "black",
tl.srt = 45,
mar=c(0, 0, 4, 0) # http://stackoverflow.com/a/14754408/54964
)
Regressie Huizenprijzen
Regressie model zou rekening moeten houden met het tijdskarakter van dit soort reeksen. We vinden hiervan voorbeelden in de econometrie (Hanck, Arnold, Gerber and Schmelzer, 2015)].
In deze studie is echter uitgegaan van een relatief eenvoudig model waarbij van de variabelen 4 kwartalen historie wordt meegenomen als mogelijke voorspellers van huizenprijzen.
#' lagdata
#'
#' Add lags to timeseries data. We assume the time serie is represented as a dataframe with column 'date'
#' This routine will then go on and add 4 lags to all variables
#'
#' @param df
#'
#' @return df
#' @export
#'
#' @examples
lagdata <- function(df){
for (name in colnames(df)) {
if (name != 'date') {
for (i in 1:4) {
variable_name = paste0(name,i)
# add lagged data to the dataframe
df[[variable_name]]= lag(df[[name]],i)
}
}
}
return (df)
}
# add lagging data to the dataframe...
# the price we need to pay is loose one year of data for the predictions...
df_rm_huizenprijzen <-
df_rm_huizenprijzen %>%
select(date,
huisprijsindex_yoy,
werkgelegenheid_yoy,
hypotheek_rente_yoy,
gdp,
consumer_conf_yoy,
inkomen_yoy) %>%
lagdata() %>%
drop_na()
# Split data set in Training and Testing set.
# Ideally we should use time slices and repeat the training for each period
df_train <- df_rm_huizenprijzen %>%
filter(date <= (max(df_rm_huizenprijzen$date) - years(5)))
df_test <- df_rm_huizenprijzen %>%
filter(date > (max(df_rm_huizenprijzen$date) - years(5)))
Regressie model voor huizenprijzen.
Lineair regressie modellen voor de verschillende indicatoren laten zien dat BBP de beste fit geeft voor de huizenprijzen. Maar de onderlinge verschillen zijn klein. De residuals na deze correlatie geven geen duidelijk patroon aan. Het lijkt daarmee alsof dit de beste enkelvoudige voorspeller is van de huisprijzen.
# lineair regression models
lm_inkomen = lm(huisprijsindex_yoy~inkomen_yoy, data = df_train)
lm_time = lm(huisprijsindex_yoy ~ date, data = df_train)
lm_werkgelegenheid = lm(huisprijsindex_yoy~werkgelegenheid_yoy, data = df_train)
lm_gdp = lm(huisprijsindex_yoy~gdp, data = df_train)
lm_rente = lm(huisprijsindex_yoy~hypotheek_rente_yoy, data = df_train)
lm_confidence = lm(huisprijsindex_yoy~consumer_conf_yoy, data = df_train)
tab_model(lm_inkomen,lm_werkgelegenheid,lm_rente,lm_gdp,lm_time, lm_confidence)
| huisprijsindex yoy | huisprijsindex yoy | huisprijsindex yoy | huisprijsindex yoy | huisprijsindex yoy | huisprijsindex yoy | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Predictors | Estimates | CI | p | Estimates | CI | p | Estimates | CI | p | Estimates | CI | p | Estimates | CI | p | Estimates | CI | p |
| (Intercept) | 0.64 | -1.26 – 2.55 | 0.505 | 1.98 | 0.56 – 3.40 | 0.007 | 5.08 | 3.88 – 6.29 | <0.001 | 0.69 | -0.72 – 2.10 | 0.336 | 18.20 | 14.03 – 22.36 | <0.001 | 4.95 | 3.75 – 6.14 | <0.001 |
| inkomen_yoy | 1.69 | 1.07 – 2.32 | <0.001 | |||||||||||||||
| werkgelegenheid_yoy | 2.40 | 1.61 – 3.19 | <0.001 | |||||||||||||||
| hypotheek_rente_yoy | 0.06 | -0.03 – 0.16 | 0.211 | |||||||||||||||
| gdp | 1.92 | 1.45 – 2.39 | <0.001 | |||||||||||||||
| date | -0.00 | -0.00 – -0.00 | <0.001 | |||||||||||||||
| consumer_conf_yoy | -2.73 | -25.71 – 20.25 | 0.814 | |||||||||||||||
| Observations | 111 | 111 | 111 | 111 | 111 | 111 | ||||||||||||
| R2 / R2 adjusted | 0.209 / 0.202 | 0.250 / 0.244 | 0.014 / 0.005 | 0.372 / 0.367 | 0.279 / 0.273 | 0.001 / -0.009 | ||||||||||||
# GDP is best fit for lineair regression
df_rm_lm <- augment(lm_gdp)
ggplot(df_rm_lm, aes(x = .fitted, y = .resid)) + geom_point()
# simple multiple regression model including all variables at T0
lm_multi = lm(huisprijsindex_yoy~date+
werkgelegenheid_yoy+
hypotheek_rente_yoy+
gdp+
consumer_conf_yoy+
inkomen_yoy, data = df_rm_huizenprijzen)
tab_model(lm_multi)
| huisprijsindex yoy | |||
|---|---|---|---|
| Predictors | Estimates | CI | p |
| (Intercept) | -1.53 | -5.62 – 2.57 | 0.462 |
| date | -0.00 | -0.00 – 0.00 | 0.549 |
| werkgelegenheid_yoy | 1.29 | 0.48 – 2.11 | 0.002 |
| hypotheek_rente_yoy | -0.12 | -0.20 – -0.05 | 0.001 |
| gdp | 1.04 | 0.52 – 1.55 | <0.001 |
| consumer_conf_yoy | 12.45 | -1.93 – 26.82 | 0.089 |
| inkomen_yoy | 1.42 | 0.94 – 1.90 | <0.001 |
| Observations | 131 | ||
| R2 / R2 adjusted | 0.476 / 0.451 | ||
# The carot model can train the best multiple regression model optimizing RMSE.
lm_compute <- train(
huisprijsindex_yoy ~ .,
data = df_train,
method = "lm",
metric = "RMSE",
trControl = trainControl(method = "cv", number = 10),
preProcess = c("zv", "center", "scale")
)
summary(lm_compute)
##
## Call:
## lm(formula = .outcome ~ ., data = dat)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.9213 -0.7878 -0.0589 0.7970 3.2367
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.935872 0.136432 36.178 < 2e-16 ***
## date 0.003562 0.200849 0.018 0.9859
## werkgelegenheid_yoy -0.526323 0.805857 -0.653 0.5156
## hypotheek_rente_yoy -0.140258 0.391700 -0.358 0.7212
## gdp 0.567831 0.455838 1.246 0.2165
## consumer_conf_yoy 0.194114 0.150972 1.286 0.2022
## inkomen_yoy 0.299737 0.332898 0.900 0.3706
## huisprijsindex_yoy1 5.139687 0.670291 7.668 3.61e-11 ***
## huisprijsindex_yoy2 0.015083 0.851374 0.018 0.9859
## huisprijsindex_yoy3 0.844826 0.866632 0.975 0.3326
## huisprijsindex_yoy4 -1.347172 0.576991 -2.335 0.0221 *
## werkgelegenheid_yoy1 0.100816 1.230976 0.082 0.9349
## werkgelegenheid_yoy2 -0.824735 1.282637 -0.643 0.5221
## werkgelegenheid_yoy3 0.128385 1.224407 0.105 0.9168
## werkgelegenheid_yoy4 1.217865 0.721207 1.689 0.0952 .
## hypotheek_rente_yoy1 -1.044295 0.627478 -1.664 0.1000 .
## hypotheek_rente_yoy2 0.093768 0.663504 0.141 0.8880
## hypotheek_rente_yoy3 -0.088587 0.612635 -0.145 0.8854
## hypotheek_rente_yoy4 0.139403 0.402163 0.347 0.7298
## gdp1 1.441493 0.624892 2.307 0.0237 *
## gdp2 0.007286 0.615305 0.012 0.9906
## gdp3 -0.533170 0.598942 -0.890 0.3760
## gdp4 0.646460 0.479396 1.348 0.1813
## consumer_conf_yoy1 0.073639 0.150648 0.489 0.6263
## consumer_conf_yoy2 -0.089078 0.148950 -0.598 0.5515
## consumer_conf_yoy3 -0.193446 0.148411 -1.303 0.1962
## consumer_conf_yoy4 -0.280546 0.147782 -1.898 0.0613 .
## inkomen_yoy1 -0.613029 0.400287 -1.531 0.1296
## inkomen_yoy2 -0.071771 0.406732 -0.176 0.8604
## inkomen_yoy3 0.277060 0.405376 0.683 0.4963
## inkomen_yoy4 0.448203 0.355055 1.262 0.2105
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.437 on 80 degrees of freedom
## Multiple R-squared: 0.9622, Adjusted R-squared: 0.9481
## F-statistic: 67.96 on 30 and 80 DF, p-value: < 2.2e-16
Met behulp van de caret library (??? Kuhn (2020)) kan een optimalisatie worden uitgevoerd om het best passende model te selecteren. We zien hier dat het model gebruik maakt van alle beschikbare data, en dan komt tot een veel betere fit op de aangeboden training data.
Tot slot is gekeken of nog een beter passend model verkregen kan worden met MARS (multivariate adaptive regression splines [Friedman (1991a, 1991b)]. Deze methode splits de regressie in meerdere ‘splines’. Waardoor in theorie een betere fit gevonden kan worden door rekening te houden met een non-lineaire relatie over de tijd.
Het MARS model kiest zelf de meest relevante parameters. Wanneer met dit model geprobeerd wordt om de prijsontwikkeling van de afgelopen 5 jaar te voorspellen geeft dit model een goede fit.
# Simple MARS model
# Tuning the model
# Optimal number of defrees and number of variables to prune is calculated
# create a tuning grid
hyper_grid <- expand.grid(
degree = 1:3,
nprune = seq(2, 100, length.out = 20) %>% floor()
)
# for reproducibiity
set.seed(123)
# cross validated model
tuned_mars <- train(
x = subset(df_train, select = -huisprijsindex_yoy),
y = df_train$huisprijsindex_yoy,
method = "earth",
metric = "RMSE",
trControl = trainControl(method = "cv", number = 10),
tuneGrid = hyper_grid
)
# plot results
ggplot(tuned_mars)
# fit model
fit <- earth(huisprijsindex_yoy~., df_train,
degree = tuned_mars$bestTune$degree, nprune = tuned_mars$bestTune$nprune)
# summarize the fit
summary(fit)
## Call: earth(formula=huisprijsindex_yoy~., data=df_train,
## degree=tuned_mars$bestTune$degree,
## nprune=tuned_mars$bestTune$nprune)
##
## coefficients
## (Intercept) 0.16301113
## h(0-huisprijsindex_yoy1) -1.39711272
## h(huisprijsindex_yoy1-0) 0.87244201
## h(10.9589-huisprijsindex_yoy4) 0.22693882
## h(0.92404-werkgelegenheid_yoy4) -1.21723757
## h(10.9589-huisprijsindex_yoy4) * h(hypotheek_rente_yoy1- -3.06748) -0.01435997
## h(-2.5463-hypotheek_rente_yoy3) * h(gdp4-2.0748) 0.13045294
##
## Selected 7 of 37 terms, and 6 of 30 predictors (nprune=7)
## Termination condition: RSq changed by less than 0.001 at 37 terms
## Importance: huisprijsindex_yoy1, hypotheek_rente_yoy3, gdp4, ...
## Number of terms at each degree of interaction: 1 4 2
## GCV 2.829426 RSS 230.0502 GRSq 0.9295437 RSq 0.9474489
# summarize the importance of input variables
evimp(fit)
## nsubsets gcv rss
## huisprijsindex_yoy1 6 100.0 100.0
## hypotheek_rente_yoy3 4 14.4 17.6
## gdp4 4 14.4 17.6
## huisprijsindex_yoy4 3 9.8 13.2
## werkgelegenheid_yoy4 2 9.2 11.3
## hypotheek_rente_yoy1 1 8.3 9.1
# make predictions for MARS model
train_predictions <- predict(fit, df_train)
test_predictions <- predict(fit, df_test)
# make predictions for our regression model
train_lm_predictions <- predict(lm_multi, df_train)
test_lm_predictions <- predict(lm_multi, df_test)
# make predictions for our ts regression model
train_lmts_predictions <- predict(lm_compute, df_train)
test_lmts_predictions <- predict(lm_compute, df_test)
df_result <-
tibble (
date = df_train$date,
huisprijsindex_yoy = df_train$huisprijsindex_yoy,
predicted = train_predictions,
variable = 'train',
model = 'MARS'
) %>%
union_all(
tibble(
date = df_test$date,
huisprijsindex_yoy = df_test$huisprijsindex_yoy,
predicted = test_predictions,
variable = 'test',
model = 'MARS')) %>%
union_all(
tibble(
date = df_train$date,
huisprijsindex_yoy = df_train$huisprijsindex_yoy,
predicted = train_lm_predictions,
variable = 'train',
model = 'LM')) %>%
union_all(
tibble(
date = df_test$date,
huisprijsindex_yoy = df_test$huisprijsindex_yoy,
predicted = test_lm_predictions,
variable = 'test',
model = 'LM')) %>%
union_all(
tibble(
date = df_train$date,
huisprijsindex_yoy = df_train$huisprijsindex_yoy,
predicted = train_lmts_predictions,
variable = 'train',
model = 'LMTS') %>%
union_all(
tibble(
date = df_test$date,
huisprijsindex_yoy = df_test$huisprijsindex_yoy,
predicted = test_lmts_predictions,
variable = 'test',
model = 'LMTS'))
)
df_result %>%
ggplot(aes(date, huisprijsindex_yoy)) +
geom_line(size = .5) +
geom_line(aes(y = predicted, color = model, linetype = variable),
size = 1, alpha = 0.8) +
scale_linetype_manual(values=c("dotted","solid"))+
labs(
title = "Voorspelling huizenprijzen MARS Model",
y = "huisprijsindex",
x = '',
color = 'dataset'
)
In dit geval geeft het lineair regressie model duidelijk een minder goede fit dan het time series model en het MARS model. Het MARS model sluit heel goed aan bij de ontwikkeling van de huizenprijzen over de afgelopen vijf jaar.
Er bestaan grote regionale verschillen in huisprijzen, en in de prijsonwikkeling over de tijd.
# boxplot
verkoopprijs_regio %>%
filter(date >= as.Date('1995-01-01')
) %>%
drop_na(verkoopprijs) %>%
mutate(verkoopprijs = verkoopprijs / 1000) %>%
ggplot(aes(y = verkoopprijs, x = jaar, fill = jaar) ) +
geom_boxplot() +
labs(title = "Distributie verkoopprijzen",
subtitle = "gemiddelde verkoopprijs per gemeente",
x = "Verkoopprijs (x 1000 eur)") +
theme(legend.position = "none") +
theme(axis.text.x = element_text(angle = 60, hjust = 1))
# Create a thematic map
verkoopprijs_regio %>%
filter(date >= as.Date('2015-01-01')
) %>%
mutate(verkoopprijs = verkoopprijs / 1000) %>%
ggplot() +
geom_sf(aes(fill = verkoopprijs)) +
facet_wrap(~jaar) +
scale_fill_viridis_c(option = "inferno") +
labs(title = "Gemiddelde verkoopprijzen woningen",
subtitle = "",
fill = "(x 1000 eur)") +
theme_void()
Het aantal transacties heeft in de crisis jaren 2009 - 2012 een duidelijke terugval laten zien. Sindsdien zien we een snele inhaalbeweging, en nog steeds zien we aanzienlijk hogere transactie volumes dan voorheen.
verkochte_woningen_per_type_per_kwartaal %>%
mutate(subtype = factor(subtype, levels=c('Vrijstaande woning',
'2-onder-1-kapwoning',
'Hoekwoning',
'Tussenwoning',
'Appartement',
'Onbekend'))) %>%
ggplot(aes(x=date, y=verkochte_bestaande_woningen )) +
geom_line(aes(color = subtype)) +
facet_wrap(~ subtype, ncol = 2, scales = "free") +
labs(
title = "Verkopen Bestaande Koopwoningen per kwartaal",
y = "",
x = '',
color = 'subtype'
) +
theme(legend.position = "none")
Wanneer we kijken naar het aantal transacties valt verder de piek op in apartementen op in Q4 2020. Dit is te verklaren door de wijziging in de regelgeving voor beleggers. Particuliere beleggens op de woningmarkt moeten vanaf 2021 8% overdrachtsbelasting betalen. Dit heeft gezorgt voor een piek aan aankopen in het laatste kwartaal van 2020. Tegelijkertijd is er begin 2021 een vrijstelling van overdrachtbelasting voor jongeren tot 35 jaar. Deze effecten van regelgeving zien we terug in de data.
Voorspellen van aantal transacties
Ook hier wordt eerst gekeken naar de correlaties tussen de variabelen. Wederom is de data omgerekend naar jaar-op-jaar percentule wijzigingen om de factoren vergelijkbaar te maken. Het aantal transacties is slechts heel beperkt gecorreleerd aan de geselecteerde variabelen.
corMatrix <- round(cor(df_rm_transactions %>%
select(-date)),5)
corCols <- c("huisprijsindex",
"Inkomen",
"werkgelegenheid",
"BBP",
"Cons.Vertrouwen",
"Aantal huishoudens",
"Aantal transacties",
"Woning tekort")
colnames(corMatrix) <- corCols
rownames(corMatrix) <- corCols
corrplot(corMatrix,
title = "Correlatie transacties",
type = "lower",
tl.cex = 0.8,
tl.col = "black",
tl.srt = 45,
mar=c(0, 0, 4, 0))
Seizoensinvloeden bij het aantal transacties
Om de seizoensinvloeden verder te analyseren heb ik een tijdreeksanalyse uitgevoerd op de data. De ACf (auto correlatie) plot toont dat meer recente data significant is, wat een trend aangeeft in de data. De PACF plot (partial auto-correlation function) toont dat recente data en seizoensinvloeden een goede indicatie geven voor het modeleren van de trend.
De uiteindelijke voorspelling laat duidelijk het seizoenspatroon zien. Verder wordt door dit model de recente trend doorgetrokken, waar eigenlijk de verwachting zou zijn dat op termijn de huizenmarkt terug keert naar een stabiel aantal transacties.
#
# vw <- verkochte_woningen_per_type_per_kwartaal %>%
# group_by (yearqtr) %>%
# summarise(totaal = sum(verkochte_bestaande_woningen) / 1000 )
# Time series object
vwts <- ts(verkochte_woningen_per_kwartaal["totaal"],
start = c(1995, 1), frequency = 4)
v1 <-
vwts %>%
autoplot() +
geom_smooth() +
labs(
title = "Verkopen Bestaande Koopwoningen per kwartaal",
y = "(x 1000)",
x = ''
)
v2 <-
vwts %>%
ggsubseriesplot() +
labs(
title = "",
y = "(x 1000)",
x = ''
)
# Plot it
cowplot::plot_grid(v1, v2, ncol=1, rel_heights = c(1, 1.5))
# Lag plot of non-seasonal effects
gglagplot(vwts, do.lines = FALSE) +
labs(
title = "Seizoensinvloeden Verkopen Bestaande Koopwoningen",
y = "",
x = '',
color = 'Quarter'
)
# ACF plot
# Visualizes how much the most recent value of the series is correlated with past values of the series
o1 <- ggAcf(vwts, lag.max = 16) +
labs(
title = "ACF Plot seizoensinvloeden Verkopen Bestaande Koopwoningen",
y = "",
x = ""
)
# PACF Plot
# Visualizes whether certain lags are good for modeling or not; useful for data with a seasonal pattern
o2 <- ggPacf(vwts, lag.max = 16) +
labs(
title = "PACF Plot seizoensinvloeden Verkopen Bestaande Koopwoningen",
y = "",
x = ""
)
# Plot both
cowplot::plot_grid(o1, o2, ncol = 1)
# Take first difference of the plot + seseonal effects
vwts %>% diff(lag=4) %>% diff() %>% ggtsdisplay(main = "Eerst orde verschil en seizoensinvloed")
# Eventualy I got this model - which seems to fit beter then auto arima
fit <-
Arima(vwts, order=c(0,1,4), seasonal=c(0,1,1))
checkresiduals(fit)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,4)(0,1,1)[4]
## Q* = 3.6063, df = 3, p-value = 0.3072
##
## Model df: 5. Total lags used: 8
fit %>%
forecast(h=12) %>%
autoplot() +
labs(
title = "Verwachting verkopen bestaande koopwoningen",
y = "",
x = ""
)
Voorspellen aantal transacties
Ook is het mogelijk om net als bij de huizenprijzen, een MARS model toe te passen op het aantal transacties. Het MARS model selecteert als de belangrijkste voorspellers: aantal huishoudens, gdp, tijdsfactor (het aantal transacties in de vorige periode) en het consumenten vertrouwen.
Het MARS model geeft op basis van deze gegevens geen goede voorspelling.
# Add Lineair regression model - for number of households and transactions...
# Add 4 lags of data
df_rm_transactions <-
df_rm_transactions %>%
lagdata() %>%
drop_na()
# Split in Train and Test data set
df_train <- df_rm_transactions %>%
filter(date <= (max(df_rm_transactions$date) - years(5)))
df_test <- df_rm_transactions %>%
filter(date > (max(df_rm_transactions$date) - years(5)))
# Tuning the model
# Optimal number of defrees and number of variables to prune is calculated
# create a tuning grid
hyper_grid <- expand.grid(
degree = 1:3,
nprune = seq(2, 100, length.out = 20) %>% floor()
)
# for reproducibiity
set.seed(123)
# cross validated model
tuned_mars <- train(
x = subset(df_train, select = -verkocht_yoy),
y = df_train$verkocht_yoy,
method = "earth",
metric = "RMSE",
trControl = trainControl(method = "cv", number = 10),
tuneGrid = hyper_grid
)
# plot results
ggplot(tuned_mars)
# fit model
fit <- earth(verkocht_yoy~., df_train,
degree = tuned_mars$bestTune$degree, nprune = tuned_mars$bestTune$nprune)
# summarize the fit
summary(fit)
## Call: earth(formula=verkocht_yoy~., data=df_train,
## degree=tuned_mars$bestTune$degree,
## nprune=tuned_mars$bestTune$nprune)
##
## coefficients
## (Intercept) -4.522249
## h(0.3887-gdp) -13.506751
## h(gdp-0.3887) -1.015497
## h(0.74537-aantal_hh_yoy) 62.947038
## h(aantal_hh_yoy-0.74537) 21.293095
## h(-7.13368-verkocht_yoy1) 1.137294
## h(verkocht_yoy1- -7.13368) 0.391478
##
## Selected 7 of 21 terms, and 3 of 40 predictors (nprune=7)
## Termination condition: RSq changed by less than 0.001 at 21 terms
## Importance: aantal_hh_yoy, gdp, verkocht_yoy1, verkocht_yoy3-unused, ...
## Number of terms at each degree of interaction: 1 6 (additive model)
## GCV 83.70006 RSS 4371.126 GRSq 0.6555393 RSq 0.7569485
# summarize the importance of input variables
evimp(fit)
## nsubsets gcv rss
## aantal_hh_yoy 6 100.0 100.0
## gdp 5 76.0 76.4
## verkocht_yoy1 4 50.1 53.1
## verkocht_yoy3-unused 1 19.6 22.3
# make predictions
train_predictions <- predict(fit, df_train)
test_predictions <- predict(fit, df_test)
df_result <-
tibble (
date = df_train$date,
verkocht_yoy = df_train$verkocht_yoy,
predicted = train_predictions,
variable = 'train'
) %>%
union_all(
tibble(
date = df_test$date,
verkocht_yoy = df_test$verkocht_yoy,
predicted = test_predictions,
variable = 'test')
)
df_result %>%
ggplot(aes(date, verkocht_yoy)) +
geom_line(size = 0.5) +
geom_line(aes(y = predicted, linetype = variable, color = 'steelblue'), size = 1) +
scale_linetype_manual(values=c("dotted","solid")) +
scale_color_manual(values=c("steelblue")) +
labs(
title = "Voorspelling aantal transacties MARS Model",
y = "Aantal transacties",
x = '',
linetype = 'dataset'
)
Ontwikkelingen vraag en aanbod
Er is in de media veel aandacht voor of de bouwplannen wel realiseerbaar zijn. Mogelijk kan door regelgeving (PFAS, ruimtelijke ordening) de groei van het aantal huizen in de toekomst de groei van de bevolking niet bijhouden waardoor het tekort tijdelijk nog verder oploopt. In deze exploratieve studie is hier niet verder op ingegaan.
Statistisch gezien is in deze studie geen verband aangetoond tussen het woning te kort en de oplopende huizenprijzen. Daarmee is geen invloed aangetoond van een verschuiving in vraag en aanbod op de prijsvorming in de huizenmarkt in Nederland.
In deze studie is met het MARS model een goede voorspelling gevonden voor de huizenprijzen in de periode 2016-2020. De belangrijkste indicatoren hierbij zijn de huizenprijzen vorige kwartaal, de hypotheekrente (3 kwartalen lag) en het bruto binnenlands product (met 4 kwartalen lag).
Om te bezien of dit model inderdaad een goede voorspelling geeft zou verder onderzoek moeten worden gedaan - waarbij andere tijdsperioden getest worden en mogelijk of het zinvol is meer lag toe te voegen aan de voorspelling.
Voor wat betreft het aantal transacties bood het MARS model in deze studie geen goede voorspelling.
CBS. (2016). Indicatoren woningmarkt op groen. Retrieved from https://www.cbs.nl/nl-nl/achtergrond/2016/16/indicatoren-woningmarkt-op-groen
CBS. (2020a). Huizenmarkt in beeld. Retrieved from https://www.cbs.nl/nl-nl/visualisaties/huizenmarkt-in-beeld
CBS. (2020b). Monitor koopwoningmarkt. Retrieved from https://www.cbs.nl/nl-nl/visualisaties/monitor-koopwoningmarkt
Foreman, J. W. (2014). Data Smart, Using Data Science to Transform Information into Insight. John Wiley & sons, Inc.
Groot, S., Vogt, B., Van der Wiel, K., & Van Dijk, M. (2018). Oververhitting op de Nederlandse huizenmarkt? Retrieved from https://www.cpb.nl/publicatie/oververhitting-op-de-nederlandse-huizenmarkt/CPB-Achtergronddocument-1jun2018-Oververhitting-op-de-nederlandse-huizenmarkt.pdf
Henry, L., & Wickham, H. (2020). Purrr: Functional programming tools. Retrieved from https://CRAN.R-project.org/package=purrr
Hyndman, R. J., & Athanasopoulos, G. (2018). Forecasting: Principles and Practice. Retrieved from https://otexts.com/fpp2/
Kenneth Gopal, Gerard van Leeuwen, David Omtzigt, T. K. en M. S.-F. (2020). Prognose woningmarktmodel Socrates. Retrieved from https://www.abfresearch.nl/publicaties/rapportage-socrates-2019/
Kenneth Gopal, Gerard van Leeuwen, David Omtzigt, T. K. en M., & Stuart-Fox. (2019). Socrates - Scenarioverkenningen van de woningmarkt in 2030. Retrieved from https://www.rijksoverheid.nl/documenten/rapporten/2019/05/29/socrates-2019---scenarioverkenningen-van-de-woningmarkt-in-2030
Léon Groenemeijer, Kenneth Gopal, D. O. &. G. van L. (2020). Vooruitzichten bevolking, huishoudens en woningmarkt, Prognose en Scenario’s 2020-2035. Retrieved from https://www.rijksoverheid.nl/documenten/rapporten/2020/06/12/vooruitzichten-bevolking-huishoudens-en-woningmarkt-prognose-en-scenarios-2020-2035
MacKay, R. J., & Oldford, R. W. (2000). Scientific method, statistical method and the speed of light. Statistical Science, 15(3), 254–278. https://doi.org/10.1214/ss/1009212817
Ministerie van Binnenlandse Zaken en Koninkrijksrelaties. (2021). Datawonen. Retrieved from https://datawonen.nl/dashboard/dashboard/koopprijs
Minister Wonen en Rijksdienst. (2016). Staat van de woningmarkt 2016. Retrieved from https://www.rijksoverheid.nl/binaries/rijksoverheid/documenten/rapporten/2016/10/31/rapport-staat-van-de-woningmarkt-2016/rapport-staat-van-de-woningmarkt-2016.pdf
Müller, K., & Wickham, H. (2021). Tibble: Simple data frames. Retrieved from https://CRAN.R-project.org/package=tibble
R Core Team. (2021). R: A language and environment for statistical computing. Vienna, Austria: R Foundation for Statistical Computing. Retrieved from https://www.R-project.org/
Research, A. (2020). Primos - Bevolkingsprognose, Rapportage Primos. Retrieved from https://www.abfresearch.nl/producten/prognoses/primos-bevolkingsprognose/
Vogt, B., Kalara, N., & Voogt, B. (2018). How do the Dutch Finance their Own House? Retrieved from https://www.cpb.nl/sites/default/files/omnidownload/CPB-Background-Document-June2018-How-do-the-dutch-finance-their-own-house.pdf
Wickham, H. (2016). Ggplot2: Elegant graphics for data analysis. Springer-Verlag New York. Retrieved from https://ggplot2.tidyverse.org
Wickham, H. (2019a). Stringr: Simple, consistent wrappers for common string operations. Retrieved from https://CRAN.R-project.org/package=stringr
Wickham, H. (2019b). Tidyverse: Easily install and load the tidyverse. Retrieved from https://CRAN.R-project.org/package=tidyverse
Wickham, H. (2021a). Forcats: Tools for working with categorical variables (factors). Retrieved from https://CRAN.R-project.org/package=forcats
Wickham, H. (2021b). Tidyr: Tidy messy data. Retrieved from https://CRAN.R-project.org/package=tidyr
Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L. D., François, R., … Yutani, H. (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686. https://doi.org/10.21105/joss.01686
Wickham, H., Chang, W., Henry, L., Pedersen, T. L., Takahashi, K., Wilke, C., … Dunnington, D. (2020). Ggplot2: Create elegant data visualisations using the grammar of graphics. Retrieved from https://CRAN.R-project.org/package=ggplot2
Wickham, H., François, R., Henry, L., & Müller, K. (2021). Dplyr: A grammar of data manipulation. Retrieved from https://CRAN.R-project.org/package=dplyr
Wickham, H., & Hester, J. (2020). Readr: Read rectangular text data. Retrieved from https://CRAN.R-project.org/package=readr